package universal.schema.action;

import com.opensymphony.xwork2.ActionContext;
import com.opensymphony.xwork2.ActionSupport;
import com.opensymphony.xwork2.Preparable;

import sun.nio.cs.ext.ISCII91;
import universal.schema.model.*;
import java.util.ArrayList;
import java.util.Map;

import universal.schema.model.Filters;

public class searchAction extends ActionSupport{

	static String[] checkTable;
	static String[] checkColumns;

	static int noWhereCheck=0;

	String where;
	String where_values[];
	String filter_operators[];
	static ArrayList<Node> nodesList = new ArrayList<Node>();
	static ArrayList<Node> selectedNodesList = new ArrayList<Node>();
	ArrayList<Node> tmp = new ArrayList<Node>();
	static ArrayList<String> getResults = new ArrayList<String>();
	ArrayList<String> Selcolumns=new ArrayList<String>();
	ArrayList<Column> SelcolumnsColTypes=new ArrayList<Column>();
	ArrayList<String> SelectedTableColumns=new ArrayList<String>();
	static int sno=1;

	String columns[];
	String operators[];
	String filtervalue[];
	String connectors[];
	ArrayList<Filters> conditions = new ArrayList<Filters>();
	ArrayList<Filters> invalid = new ArrayList<Filters>();  //invalid conditions
	int flag=0; 
	boolean connectivityFlag=false;
	boolean connectivityFlagAssociation=false;
	String invalid_cntrs="";

	ArrayList<String> operatorsList;
	String operator="";

	Map session=ActionContext.getContext().getSession();

	//adding new variables
	String columns1;
	String operators1;
	String filtervalue1;
	String connectors1;

	public searchAction()
	{
		operatorsList=new ArrayList<String>();
		operatorsList.add("<");
		operatorsList.add(">");
		operatorsList.add("=");
		operatorsList.add("<=");
		operatorsList.add(">=");
		operatorsList.add("!=");
		operatorsList.add("equals");
		operatorsList.add("contains");
		operatorsList.add("starts-with");
		/*
		operatorsList.add("is");
		operatorsList.add("not is");*/
	}

	@SuppressWarnings("unchecked")
	public String checkWhere(){
		//check if user has not made any selections
		if(checkColumns==null || checkColumns.length==0){
			return "error";
		}

		//set user selected cols in session
		session.put("selectedColumns",checkColumns);
		return SUCCESS;
	}

	public String welcome(){
		return SUCCESS;
	}

	public String execute() throws Exception {

		// initializing hash bucket and fetching
		
		if(nodesList.size()==0)
		{
			
			nodesList = Graph.initHashBucket();
			Graph.createLinks();
		}//System.out.println("use has selected tables.");
		return SUCCESS;
	}

	public String step1_5() throws Exception
	{
		//checking if user has made any selections
		if(checkTable != null)
			System.out.println("checkTable.length: "+checkTable.length);

		if(checkTable == null || checkTable.length==0){
			return "error";
		}

		Graph.getLinker_nodes().clear();

		execute();

		ArrayList<Node> test;

		/* checking the connectivity*/		
		int j,i;
		int noOfTables = checkTable.length;
		int countTables=0;//to count the no of matching tables

		if(noOfTables == 1)
			connectivityFlag=true;
		else{
			for(i=0;i<noOfTables;i++){
				for(j=0;j<noOfTables;j++){

					Graph.getLinker_nodes().clear();//clear the linker node before calling the method
					Graph.getLinker_nodes_association().clear();

					if(Graph.isConnected(checkTable[i],checkTable[i],checkTable[j])){
						//get all the tables in the connected path and check 
						//if the user selected tables are subset of this path, then make the connectivity flag as true 	
						//checking n^2 no of time so that all the combinations are checked...

						for(int k=0;k<checkTable.length;k++){						
							for(int l=0;l<Graph.getLinker_nodes().size();l++){
								if(Graph.getLinker_nodes().get(l).getTblObj().getName().equalsIgnoreCase(checkTable[k])){
									countTables++;
								}
							}
						} 

						if(countTables==checkTable.length && countTables<=Graph.getLinker_nodes().size()){
							//if number of matching tables are equal to selected tables and less than linker tables size then set flag to true  
							Graph g=new Graph();
							g.trial(Graph.getLinker_nodes());
							session.put("finalJoinPath", g.getJoin_keys()); //conatins all Pks and Fk except source for the path found
							connectivityFlag=true;
							break;
						}//end of if for subset check
						else
						{
							countTables=0;
						}
					}

				} //end of inner for j loop

				if(connectivityFlag==true) break;

			}//end outer for loop i


			//Association check
			if(connectivityFlag == false)
			{
				for( i=0;i<noOfTables;i++){
					for(j=0;j<noOfTables;j++){

						Graph.getLinker_nodes().clear();//clear the linker node before calling the method
						Graph.getLinker_nodes_association().clear();

						//checking association relationship between classes
						if(Graph.isAssociation(checkTable[i],checkTable[j])){

							for(int k=0;k<checkTable.length;k++){
								for(int l=0;l<Graph.getLinker_nodes_association().size();l++){
									if(Graph.getLinker_nodes_association().get(l).getTblObj().getName().equalsIgnoreCase(checkTable[k])){
										countTables++;

									}
								}
							} 
							System.out.println("Count tables="+countTables);	
							if(countTables==checkTable.length && countTables<=Graph.getLinker_nodes_association().size()){
								//if number of matching tables are equal to selected tables and less than linker tables size then set flag to true  

								session.put("finalJoinPathAssociation",Graph.getLinker_nodes_association()); //conatins all Pks and Fk except source for the path found
								connectivityFlagAssociation=true;

								break;
							}//end of if for subset check
							else
							{
								countTables=0;
							}


						}

					} //end of inner for j loop

					if(connectivityFlagAssociation==true) break;

				}//end outer for loop i

			}
		}
		if( connectivityFlag==false && connectivityFlagAssociation==false){
			return "invalid";
		}

		return SUCCESS;
	}


	public String fetchColumns() throws Exception {
		int i,j;

		//putting all user selected tables in session
		//if(!session.containsKey("selectedTables"))
		session.put("selectedTables",checkTable);

		nodesList.clear();
		Selcolumns.clear();

		nodesList = Graph.initHashBucket();

		//	 navigating nodesList to find the selectedNodes 
		for (i = 0; i < nodesList.size(); i++) {

			for ( j = 0; j < checkTable.length; j++) {
				//matching tbl names
				if (nodesList.get(i).getTblObj().getName().equalsIgnoreCase(checkTable[j])) {
					selectedNodesList.add(nodesList.get(i));
				}
			}
		}

		session.put("selectedNodesList", selectedNodesList);

		for (int k = 0; k < selectedNodesList.size(); k++) {
			for(int l=0;l < selectedNodesList.get(k).getTblObj().getColumns().size();l++)
			{
				//do not show keys
				if(selectedNodesList.get(k).getTblObj().getColumns().get(l).getDataType().equalsIgnoreCase("NK"))
				{
					//All the columns of selected table

					//only columns names of all tables selected
					Selcolumns.add(selectedNodesList.get(k).getTblObj().getColumns().get(l).getColName());

					Column cobj=new Column();
					cobj.setColName(selectedNodesList.get(k).getTblObj().getColumns().get(l).getColName());
					cobj.setColType(selectedNodesList.get(k).getTblObj().getColumns().get(l).getColType());
					cobj.setDataType("");
					SelcolumnsColTypes.add(cobj); //actual column objects
				}
			}
		}

		session.put("ColsOfSelectedTablesLength",Selcolumns.size()); // count of all cols of all tbls selectd
		session.put("Colsdatatypes",SelcolumnsColTypes); //actual cols object of all selectd tbles

		// putting all cols of selected tables in session (converting to String[] first)
		String[] colsofSelTbls= new String[Selcolumns.size()];

		for(int k=0;k<Selcolumns.size();k++)
			colsofSelTbls[k]= Selcolumns.get(k).toString();

		session.put("ColsOfSelectedTables", colsofSelTbls); 

		return SUCCESS;
	}


	//function to add new condition to arraylist condition

	public String addConditionNEW(){

		Filters tempObj = new Filters();
		tempObj.setColumns(columns1);
		tempObj.setConnectors(connectors1);
		tempObj.setFiltervalue(filtervalue1);
		tempObj.setOperators(operators1);

		conditions.add(tempObj);
		System.out.println("Condition size: "+conditions.size());

		return SUCCESS;
	}

	@SuppressWarnings("unchecked")
	public String getFilterConditions() throws Exception{

		if(SelectedTableColumns.size()!=0)
			SelectedTableColumns.clear();

		int arrayLength = Integer.parseInt(session.get("ColsOfSelectedTablesLength").toString());
		String[] array=(String[])session.get("ColsOfSelectedTables");

		for(int j=0;j<arrayLength;j++){
			SelectedTableColumns.add(array[j]);	
		}

		//put arraylist of cols in session - for where condition
		session.put("selectedtablecolumns",SelectedTableColumns);

		return SUCCESS;
	}


	public String filterUtils()
	{
		flag=0; //resetting flag for consecutive runs

		for(int i=0;i<columns.length;i++)
		{
			//valid
			if(!  (columns[i].equalsIgnoreCase("-1") && operators[i].equalsIgnoreCase("-1") && filtervalue[i].isEmpty() && connectors[i].equalsIgnoreCase("-1")))
			{
				Filters obj=new Filters();
				obj.setColumns(columns[i]);
				obj.setOperators(operators[i]);
				obj.setFiltervalue(filtervalue[i]);

				if(connectors[i].equalsIgnoreCase("1"))
					obj.setConnectors("AND");
				else if(connectors[i].equalsIgnoreCase("2"))
					obj.setConnectors("OR");
				else
					obj.setConnectors(connectors[i]); // -1

				conditions.add(obj);
			}
		}

		int len=conditions.size();

		//invalids
		for(int i=0;i<len;i++)
		{
			//checking all 4 conditions for 0 to n-2 rows
			if((i<len-1) && (conditions.get(i).getColumns().equalsIgnoreCase("-1") || conditions.get(i).getOperators().equalsIgnoreCase("-1") || conditions.get(i).getFiltervalue().isEmpty() || conditions.get(i).getConnectors().equalsIgnoreCase("-1") ))
			{
				invalid.add(conditions.get(i));
				invalid_cntrs=invalid_cntrs.concat(i+";");
				flag=1;
			}
			else
			{
				if(i==(len-1))
				{
					//setting connector value for last row to -1

					conditions.get(i).setConnectors("-1");
					//checking only first 3 conditions for last row
					if(conditions.get(i).getColumns().equalsIgnoreCase("-1") || conditions.get(i).getOperators().equalsIgnoreCase("-1") || conditions.get(i).getFiltervalue().isEmpty())
					{

						invalid.add(conditions.get(i));
						invalid_cntrs=invalid_cntrs.concat(i+"");
						flag=1;

					}
				}
			}
		}

		//removing invalid entries from conditions
		if(invalid.size()!=0)
		{
			invalid_cntrs=invalid_cntrs.trim();
			String tmp[]=invalid_cntrs.split(";");
			for(int i=tmp.length-1;i>=0;i--)
			{
				conditions.remove(Integer.parseInt(tmp[i]));
			}

		}

		if (conditions.size()==0)
		{
			return "start";
		}

		else if(flag==0){
			//all valids
			session.put("finalFilters", conditions);
			return "success";
		}
		else  
		{
			//few valids
			session.put("finalFilters", conditions);
			return "error";
		}
	}

	public String filterCreation()
	{
		if(conditions.size()==0) //first time entry
		{
			return filterUtils();

		} //end of if
		else // go back and correct
		{
			invalid_cntrs=""; //reset for next run
			invalid.clear(); //reset for next run
			//reset form

			return filterUtils();
		}
	}

	
	
	
	public ArrayList<Filters> getInvalid() {
		return invalid;
	}

	public void setInvalid(ArrayList<Filters> invalid) {
		this.invalid = invalid;
	}

	public ArrayList<Filters> getConditions() {
		return conditions;
	}

	public void setConditions(ArrayList<Filters> conditions) {
		this.conditions = conditions;
	}

	public ArrayList<String> getSelectedTableColumns() {
		return SelectedTableColumns;
	}

	public void setSelectedTableColumns(ArrayList<String> selectedTableColumns) {
		SelectedTableColumns = selectedTableColumns;
	}
	public ArrayList<String> getGetResults() {
		return getResults;
	}

	public void setGetResults(ArrayList<String> getResults) {
		this.getResults = getResults;
	}

	public String[] getWhere_values() {
		return where_values;
	}

	public void setWhere_values(String[] where_values) {
		this.where_values = where_values;
	}

	public String[] getFilter_operators() {
		return filter_operators;
	}

	public void setFilter_operators(String[] filter_operators) {
		this.filter_operators = filter_operators;
	}

	public String getWhere() {
		return where;
	}

	public void setWhere(String where) {
		this.where = where;
	}

	public String[] getCheckColumns() {
		return checkColumns;
	}

	public void setCheckColumns(String[] checkColumns) {
		this.checkColumns = checkColumns;
	}

	public ArrayList<Node> getSelectedNodesList() {
		return selectedNodesList;
	}

	public void setSelectedNodesList(ArrayList<Node> selectedNodesList) {
		this.selectedNodesList = selectedNodesList;
	}

	public String getOperator() {
		return operator;
	}

	public void setOperator(String operator) {
		this.operator = operator;
	}

	public ArrayList<Node> getNodesList() {
		return nodesList;
	}

	public void setNodesList(ArrayList<Node> nodesList) {
		this.nodesList = nodesList;
	}

	public String[] getCheckTable() {
		return checkTable;
	}

	public void setCheckTable(String[] checkTable) {
		this.checkTable = checkTable;
	}


	public String[] getColumns() {
		return columns;
	}

	public void setColumns(String[] columns) {
		this.columns = columns;
	}

	public String[] getOperators() {
		return operators;
	}

	public void setOperators(String[] operators) {
		this.operators = operators;
	}

	public String[] getFiltervalue() {
		return filtervalue;
	}

	public void setFiltervalue(String[] filtervalue) {
		this.filtervalue = filtervalue;
	}

	public String[] getConnectors() {
		return connectors;
	}

	public void setConnectors(String[] connectors) {
		this.connectors = connectors;
	}

	public ArrayList<String> getSelcolumns() {
		return Selcolumns;
	}


	public void setSelcolumns(ArrayList<String> selcolumns) {
		Selcolumns = selcolumns;
	}

	public ArrayList<Column> getSelcolumnsColTypes() {
		return SelcolumnsColTypes;
	}

	public void setSelcolumnsColTypes(ArrayList<Column> selcolumnsColTypes) {
		SelcolumnsColTypes = selcolumnsColTypes;
	}

	public int getFlag() {
		return flag;
	}

	public void setFlag(int flag) {
		this.flag = flag;
	}

	public static int getSno() {
		return sno;
	}

	public static void setSno(int sno) {
		searchAction.sno = sno;
	}

	public boolean isConnectivityFlag() {
		return connectivityFlag;
	}

	public void setConnectivityFlag(boolean connectivityFlag) {
		this.connectivityFlag = connectivityFlag;
	}

	public ArrayList<String> getOperatorsList() {
		return operatorsList;
	}

	public void setOperatorsList(ArrayList<String> operatorsList) {
		this.operatorsList = operatorsList;
	}

	public String getColumns1() {
		return columns1;
	}

	public void setColumns1(String columns1) {
		this.columns1 = columns1;
	}

	public String getOperators1() {
		return operators1;
	}

	public void setOperators1(String operators1) {
		this.operators1 = operators1;
	}

	public String getFiltervalue1() {
		return filtervalue1;
	}

	public void setFiltervalue1(String filtervalue1) {
		this.filtervalue1 = filtervalue1;
	}

	public String getConnectors1() {
		return connectors1;
	}

	public void setConnectors1(String connectors1) {
		this.connectors1 = connectors1;
	}
}
